﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace SynchronizedPlayer
{ 
    abstract class Command
    {
        public static int Size { get { return 0; } }
        public static readonly char[] FIELD_SEPARATOR = {' '};
        public static Dictionary<String,Type> AllCommands {get; private set; }


        public static void BuildDictionary()
        {
            AllCommands = new Dictionary<string,Type>();
            foreach (var t in Assembly.GetExecutingAssembly().GetTypes())
            {
                CommandInfo attr = (CommandInfo)Attribute.GetCustomAttribute(t, typeof(CommandInfo));
                if (attr != null)
                {
                    AllCommands.Add(attr.Name, t);
                }
            }
        }

        public byte[] ToByteArray()
        {
            string repr = this.ToString();

            byte[] res = new byte[Encoding.ASCII.GetByteCount(repr) + 1];
            res[0] = (byte)(repr.Length);
            Encoding.ASCII.GetBytes(repr).CopyTo(res, 1);
            return res;
        }

        public static Command Parse(byte[] buffer)
        {
            string repr = System.Text.Encoding.ASCII.GetString(buffer);

            return Parse(repr);
        }

        public static Command Parse(string cmd)
        {
            string[] repr = cmd.Split( FIELD_SEPARATOR );

            return (Command)Activator.CreateInstance(
                    AllCommands.First(kvp => kvp.Key == repr[0])
                                    .Value,
                                    new object[] { repr }
                    );  
        }
    }

    [CommandInfo(Name="setpos")]
    class CMDSetPosition : Command
    {
        public string Hash { get; private set; }
        public string Position { get; private set; }


        public CMDSetPosition(string[] repr)
        {
            Hash = repr[1].ToString();
            Position = repr[2].ToString();
        }
        public override string ToString()
        {
            return AllCommands.First(kvp => kvp.Value == this.GetType()).Key
                + FIELD_SEPARATOR[0] + Hash
                + FIELD_SEPARATOR[0] + Position;
        }
        
    }
    [CommandInfo(Name="plbegin")]
    class CMDPlaylistBegin : Command
    {
        public string CurrentTrack { get; private set; }
        public string Position { get; private set; }

        public CMDPlaylistBegin(string[] repr)
        {
            CurrentTrack = repr[1].ToString();
            Position = repr[2].ToString();
        }
        public CMDPlaylistBegin(string currentTrack, string position)
        {
            CurrentTrack = currentTrack;
            Position = position;
        }
        public override string ToString()
        {
            return AllCommands.First(kvp => kvp.Value == this.GetType()).Key
                + FIELD_SEPARATOR[0] + CurrentTrack + FIELD_SEPARATOR[0] + Position;
        }
       
    }

    [CommandInfo(Name = "plend")]
    class CMDPlaylistEnd : Command
    {
        public CMDPlaylistEnd(string[] repr) { }
        public CMDPlaylistEnd() { }

        public override string ToString()
        {
            return AllCommands.First(kvp => kvp.Value == this.GetType()).Key;
        }
    }

    [CommandInfo(Name = "plitem")]
    class CMDPlaylistItem : Command
    {
        public string Hash { get; private set; }
        public CMDPlaylistItem(string[] repr)
        {
            Hash = repr[1];
        }
        public CMDPlaylistItem(string item)
        {
            Hash = item;
        }


        public override string ToString()
        {
            return AllCommands.First(kvp => kvp.Value == this.GetType()).Key + FIELD_SEPARATOR[0] + Hash;
        }

    }
}

